<?php
/**
 * 管理员组服务层
 *
 * @author Claude Code
 * @since 2025-11-03
 */

namespace app\service;

use app\model\admin\AdminGroup;
use app\model\admin\User;
use think\facade\Db;
use think\exception\ValidateException;

/**
 * 管理员组业务逻辑处理
 *
 * 主要职责：
 * 1. 管理员组数据的增删改查
 * 2. 权限规则管理
 * 3. 管理员组成员管理
 * 4. 缓存管理
 */
class AdminGroupService extends BaseService
{
    /**
     * 管理员组模型
     * @var AdminGroup
     */
    protected $groupModel;

    /**
     * 用户模型
     * @var User
     */
    protected $userModel;

    /**
     * 缓存键前缀
     */
    protected const CACHE_PREFIX = 'admin_group:';

    /**
     * 缓存过期时间
     */
    protected const CACHE_EXPIRE = 3600;

    /**
     * 构造函数
     */
    public function __construct()
    {
        $this->groupModel = new AdminGroup();
        $this->userModel = new User();

        $this->setModel($this->groupModel);
        $this->setCacheConfig(true, self::CACHE_PREFIX, self::CACHE_EXPIRE);
    }

    /**
     * 获取管理员组列表
     * @param array $params 查询参数
     * @param bool $useCache 是否使用缓存
     * @return array
     */
    public function getGroupList(array $params = [], bool $useCache = true): array
    {
        $cacheKey = 'list:' . md5(serialize($params));

        if ($useCache) {
            $cached = $this->getCache($cacheKey);
            if ($cached !== null) {
                $this->logInfo('从缓存获取管理员组列表', ['params' => $params]);
                return $cached;
            }
        }

        // 构建查询条件
        $where = [];

        if (!empty($params['keywords'])) {
            $where[] = ['title|desc', 'like', '%' . $params['keywords'] . '%'];
        }

        if (isset($params['status']) && $params['status'] !== '') {
            $where[] = ['status', '=', (int)$params['status']];
        }

        // 查询管理员组列表
        $query = Db::name('admin_group')
            ->where($where)
            ->order('create_time', 'asc');

        $total = $query->count();
        $page = (int)($params['page'] ?? 1);
        $limit = (int)($params['limit'] ?? 20);

        $groups = $query->page($page, $limit)->select()->toArray();

        // 处理数据格式
        foreach ($groups as &$group) {
            $group = $this->formatGroupData($group);
        }

        $result = [
            'list' => $groups,
            'total' => $total,
            'page' => $page,
            'limit' => $limit,
            'pages' => ceil($total / $limit)
        ];

        if ($useCache) {
            $this->setCache($cacheKey, $result);
        }

        $this->logInfo('获取管理员组列表成功', [
            'count' => count($groups)
        ]);

        return $result;
    }

    /**
     * 格式化管理员组数据
     * @param array $group 原始数据
     * @return array
     */
    protected function formatGroupData(array $group): array
    {
        $group['create_time_format'] = $group['create_time'] ? date('Y-m-d H:i:s', $group['create_time']) : '';
        $group['update_time_format'] = $group['update_time'] ? date('Y-m-d H:i:s', $group['update_time']) : '';

        // 状态名称
        $statusNames = [
            0 => '禁用',
            1 => '正常'
        ];
        $group['status_name'] = $statusNames[$group['status']] ?? '未知';

        // 权限节点
        if (!empty($group['rules'])) {
            $rulesArray = explode(',', trim($group['rules'], ','));
            $group['rules_array'] = array_filter($rulesArray);
            $group['rules_count'] = count($group['rules_array']);
        } else {
            $group['rules_array'] = [];
            $group['rules_count'] = 0;
        }

        // 首页展示模块
        if (!empty($group['layouts'])) {
            $layoutsArray = explode(',', trim($group['layouts'], ','));
            $group['layouts_array'] = array_filter($layoutsArray);
            $group['layouts_count'] = count($group['layouts_array']);
        } else {
            $group['layouts_array'] = [];
            $group['layouts_count'] = 0;
        }

        // 使用该用户组的用户数量
        $group['user_count'] = Db::name('admin')
            ->where('group_id', $group['id'])
            ->where('status', '>=', 0)
            ->count();

        return $group;
    }

    /**
     * 获取管理员组详情
     * @param int $id 管理员组ID
     * @param bool $useCache 是否使用缓存
     * @return array|null
     */
    public function getGroupInfo(int $id, bool $useCache = true): ?array
    {
        if ($id <= 0) {
            return null;
        }

        $cacheKey = "info:{$id}";

        if ($useCache) {
            $cached = $this->getCache($cacheKey);
            if ($cached !== null) {
                return $cached;
            }
        }

        $group = Db::name('admin_group')
            ->where('id', $id)
            ->find();

        if (!$group) {
            return null;
        }

        $group = $this->formatGroupData($group);

        // 获取用户组的具体权限节点信息
        if (!empty($group['rules_array'])) {
            $group['rules_detail'] = Db::name('admin_rule')
                ->whereIn('id', $group['rules_array'])
                ->field('id, title, name, src, module')
                ->select()
                ->toArray();
        } else {
            $group['rules_detail'] = [];
        }

        // 获取使用该用户组的用户列表（前20个）
        $users = Db::name('admin')
            ->field('id, name, username, did, status')
            ->where('group_id', $id)
            ->where('status', '>=', 0)
            ->limit(20)
            ->select()
            ->toArray();

        $group['users'] = $users;

        if ($useCache) {
            $this->setCache($cacheKey, $group);
        }

        return $group;
    }

    /**
     * 创建管理员组
     * @param array $data 管理员组数据
     * @return int 管理员组ID
     * @throws ValidateException
     */
    public function createGroup(array $data): int
    {
        // 数据验证
        $this->validateGroupData($data);

        // 检查管理员组名称是否已存在
        $existing = Db::name('admin_group')
            ->where('title', trim($data['title']))
            ->find();

        if ($existing) {
            throw new ValidateException('管理员组名称已存在');
        }

        return $this->transaction(function () use ($data) {
            // 处理权限规则字符串
            $rules = isset($data['rules']) && is_array($data['rules'])
                ? ',' . implode(',', array_filter($data['rules'])) . ','
                : '';

            $layouts = isset($data['layouts']) && is_array($data['layouts'])
                ? ',' . implode(',', array_filter($data['layouts'])) . ','
                : '';

            $groupData = [
                'title' => trim($data['title']),
                'status' => (int)($data['status'] ?? 1),
                'rules' => $rules,
                'layouts' => $layouts,
                'desc' => trim($data['desc'] ?? ''),
                'create_time' => time(),
                'update_time' => time()
            ];

            $groupId = Db::name('admin_group')->insertGetId($groupData);

            // 清除相关缓存
            $this->clearGroupCache();

            $this->logInfo('创建管理员组成功', ['group_id' => $groupId, 'title' => $data['title']]);

            return $groupId;
        });
    }

    /**
     * 更新管理员组
     * @param int $id 管理员组ID
     * @param array $data 管理员组数据
     * @return bool
     * @throws ValidateException
     */
    public function updateGroup(int $id, array $data): bool
    {
        if ($id <= 0) {
            throw new ValidateException('管理员组ID不能为空');
        }

        // 检查管理员组是否存在
        $group = Db::name('admin_group')->where('id', $id)->find();
        if (!$group) {
            throw new ValidateException('管理员组不存在');
        }

        // 数据验证
        $this->validateGroupData($data, $id);

        // 检查管理员组名称是否已存在（排除自己）
        if (isset($data['title'])) {
            $existing = Db::name('admin_group')
                ->where('title', trim($data['title']))
                ->where('id', '<>', $id)
                ->find();

            if ($existing) {
                throw new ValidateException('管理员组名称已存在');
            }
        }

        return $this->transaction(function () use ($id, $data, $group) {
            // 处理权限规则字符串
            $rules = isset($data['rules']) && is_array($data['rules'])
                ? ',' . implode(',', array_filter($data['rules'])) . ','
                : $group['rules'];

            $layouts = isset($data['layouts']) && is_array($data['layouts'])
                ? ',' . implode(',', array_filter($data['layouts'])) . ','
                : $group['layouts'];

            $updateData = [
                'title' => trim($data['title'] ?? $group['title']),
                'status' => (int)($data['status'] ?? $group['status']),
                'rules' => $rules,
                'layouts' => $layouts,
                'desc' => trim($data['desc'] ?? $group['desc']),
                'update_time' => time()
            ];

            $result = Db::name('admin_group')->where('id', $id)->update($updateData) > 0;

            // 清除相关缓存
            $this->clearGroupCache();

            $this->logInfo('更新管理员组成功', ['group_id' => $id]);

            return $result;
        });
    }

    /**
     * 删除管理员组（软删除）
     * @param int $id 管理员组ID
     * @return bool
     * @throws ValidateException
     */
    public function deleteGroup(int $id): bool
    {
        if ($id <= 0) {
            throw new ValidateException('管理员组ID不能为空');
        }

        // 检查管理员组是否存在
        $group = Db::name('admin_group')->where('id', $id)->find();
        if (!$group) {
            throw new ValidateException('管理员组不存在');
        }

        // 检查是否有用户使用该管理员组
        $userCount = Db::name('admin')
            ->where('group_id', $id)
            ->where('status', '>=', 0)
            ->count();

        if ($userCount > 0) {
            throw new ValidateException("该用户组下有{$userCount}个用户，不能删除");
        }

        return $this->transaction(function () use ($id) {
            $result = Db::name('admin_group')->where('id', $id)->delete() > 0;

            // 清除相关缓存
            $this->clearGroupCache();

            $this->logInfo('删除管理员组成功', ['group_id' => $id]);

            return $result;
        });
    }

    /**
     * 验证管理员组数据
     * @param array $data 数据
     * @param int|null $id 管理员组ID（更新时）
     * @return void
     * @throws ValidateException
     */
    protected function validateGroupData(array $data, ?int $id = null): void
    {
        if (empty($data['title'])) {
            throw new ValidateException('管理员组名称不能为空');
        }

        $titleLength = mb_strlen(trim($data['title']));
        if ($titleLength < 2) {
            throw new ValidateException('管理员组名称不能少于2个字符');
        }

        if ($titleLength > 50) {
            throw new ValidateException('管理员组名称不能超过50个字符');
        }

        // 校验权限节点是否存在
        if (isset($data['rules']) && is_array($data['rules'])) {
            $validRules = Db::name('admin_rule')
                ->whereIn('id', array_filter($data['rules']))
                ->column('id');

            $invalidRules = array_diff(array_filter($data['rules']), $validRules);
            if (!empty($invalidRules)) {
                throw new ValidateException('权限节点ID不存在：' . implode(',', $invalidRules));
            }
        }
    }

    /**
     * 清除管理员组相关缓存
     * @return void
     */
    protected function clearGroupCache(): void
    {
        $this->clearCache('admin_group');
    }

    /**
     * 获取启用的管理员组列表（用于下拉选择）
     * @return array
     */
    public function getActiveGroups(): array
    {
        $cacheKey = 'active';

        $cached = $this->getCache($cacheKey);
        if ($cached !== null) {
            return $cached;
        }

        $groups = Db::name('admin_group')
            ->field('id, title, desc')
            ->where('status', 1)
            ->order('create_time', 'asc')
            ->select()
            ->toArray();

        // 计算权限节点数量
        foreach ($groups as &$group) {
            if (!empty($group['rules'])) {
                $rulesArray = explode(',', trim($group['rules'], ','));
                $group['rules_count'] = count(array_filter($rulesArray));
            } else {
                $group['rules_count'] = 0;
            }
        }

        $this->setCache($cacheKey, $groups);

        return $groups;
    }

    /**
     * 批量更新管理员组状态
     * @param array $ids 管理员组ID数组
     * @param int $status 状态
     * @return int 更新数量
     */
    public function batchUpdateStatus(array $ids, int $status): int
    {
        if (empty($ids)) {
            return 0;
        }

        $updateCount = Db::name('admin_group')
            ->where('id', 'in', $ids)
            ->update([
                'status' => $status,
                'update_time' => time()
            ]);

        if ($updateCount) {
            $this->clearGroupCache();
            $this->logInfo('批量更新管理员组状态成功', [
                'ids' => $ids,
                'status' => $status,
                'count' => $updateCount
            ]);
        }

        return $updateCount;
    }

    /**
     * 搜索管理员组
     * @param string $keyword 关键词
     * @param int $limit 限制数量
     * @return array
     */
    public function searchGroups(string $keyword, int $limit = 20): array
    {
        if (empty($keyword)) {
            return [];
        }

        $groups = Db::name('admin_group')
            ->field('id, title, desc, status')
            ->where('title|desc', 'like', '%' . $keyword . '%')
            ->limit($limit)
            ->order('id', 'desc')
            ->select()
            ->toArray();

        return $groups;
    }

    /**
     * 获取管理员组统计信息
     * @return array
     */
    public function getGroupStats(): array
    {
        $stats = [
            'total' => Db::name('admin_group')->count(),
            'active' => Db::name('admin_group')->where('status', 1)->count(),
            'inactive' => Db::name('admin_group')->where('status', 0)->count()
        ];

        // 获取各用户组的用户数量统计
        $groupStats = Db::name('admin_group')
            ->alias('g')
            ->field('g.id, g.title, COUNT(a.id) as user_count')
            ->leftJoin('admin a', 'g.id = a.group_id AND a.status >= 0')
            ->group('g.id')
            ->select()
            ->toArray();

        $stats['group_stats'] = $groupStats;

        return $stats;
    }

    /**
     * 检查用户是否有权限
     * @param int $userId 用户ID
     * @param string $ruleName 权限规则名
     * @return bool
     */
    public function checkUserPermission(int $userId, string $ruleName): bool
    {
        // 获取用户信息
        $user = Db::name('admin')
            ->where('id', $userId)
            ->where('status', '>=', 0)
            ->find();

        if (!$user) {
            return false;
        }

        // 超级管理员拥有所有权限
        if ($user['id'] == 1) {
            return true;
        }

        // 获取用户组信息
        $group = Db::name('admin_group')
            ->where('id', $user['group_id'])
            ->where('status', 1)
            ->find();

        if (!$group || empty($group['rules'])) {
            return false;
        }

        // 检查权限规则是否存在
        $rule = Db::name('admin_rule')
            ->where('name', $ruleName)
            ->where('status', 1)
            ->find();

        if (!$rule) {
            return false;
        }

        // 检查用户组是否包含该权限
        $rulesArray = explode(',', trim($group['rules'], ','));
        return in_array($rule['id'], $rulesArray);
    }
}
